#ifndef __OARRAY_H
#define __OARRAY_H
#include "stdtype.h"
#include "dlist.h"
#include "assert.h"

/**
 * this function will get the next node
 * @prototype: mx_oarray_node_pt mx_oarray_node_next(mx_oarray_node_pt);
 * @note: make sure that the specified node in an array
 */
#define mx_oarray_node_next(node) ({ \
    assert_true((node)->owner != mx_null);    \
    mx_oarray_node_pt ret;   \
    if (mx_dlist_next(node) == &((node)->owner->dlist)) {   \
        ret = (mx_oarray_node_pt)(mx_dlist_next((node)->owner));  \
    } else {    \
        ret = (mx_oarray_node_pt)(mx_dlist_next(node)); \
    }   \
    ret;    \
})

/**
 * this function will get the prev node
 * @prototype: mx_oarray_node_pt mx_oarray_node_prev(mx_oarray_node_pt);
 * @note: make sure that the specified node in an array
 */
#define mx_oarray_node_prev(node) ({ \
    assert_true((node)->owner != mx_null);    \
    mx_oarray_node_pt ret;   \
    if (mx_dlist_prev(node) == &((node)->owner->dlist)) {   \
        ret = (mx_oarray_node_pt)(mx_dlist_prev((node)->owner));  \
    } else {    \
        ret = (mx_oarray_node_pt)(mx_dlist_prev(node)); \
    }   \
    ret;    \
})

/**
 * this function will iterate the specified array (order, ->next)
 * @prototype: void mx_oarray_foreach (mx_oarray_pt, <node>, {...});
 * @note: do not change the struct of double list, such as remove or insert nodes
 */
#define mx_oarray_foreach(array, node, ...) {    \
    for (mx_dlist_pt next = mx_dlist_next(array); next != &(array)->dlist; next = mx_dlist_next(next)) {   \
        mx_oarray_node_pt node = (mx_oarray_node_pt)next;    \
        __VA_ARGS__ \
    }   \
}

/**
 * this function will iterate the specified array (reverse, ->prev)
 * @prototype: void mx_oarray_foreach_prev (mx_oarray_pt, <node>, {...});
 * @note: do not change the struct of double list, such as remove or insert nodes
 */
#define mx_oarray_foreach_prev(array, node, ...) {    \
    for (mx_dlist_pt prev = mx_dlist_prev(array); prev != &(array)->dlist; prev = mx_dlist_prev(prev)) {   \
        mx_oarray_node_pt node = (mx_oarray_node_pt)prev;    \
        __VA_ARGS__ \
    }   \
}

/**
 * get the first node of order array
 */
#define mx_oarray_firstnode(array) ((mx_oarray_node_pt)mx_dlist_next(array))

/**
 * get the last node of order array
 */
#define mx_oarray_lastnode(array) ((mx_oarray_node_pt)mx_dlist_prev(array))

typedef enum
{
    MX_OARRAY_SORT_NONE = 0,    // none order
    MX_OARRAY_SORT_ASCE,        // ascending order
    MX_OARRAY_SORT_DESC         // descending order
} mx_oarray_sort_t;

typedef struct
{
    mx_dlist_t dlist;           // this propertiy must be in the first place
    mx_oarray_sort_t sort;
    mx_size_t count;
} mx_oarray_t, *mx_oarray_pt;

typedef struct
{
    mx_dlist_t dlist;           // this propertiy must be in the first place
    mx_usize_t seque;
    mx_oarray_pt owner;
} mx_oarray_node_t, *mx_oarray_node_pt;

void mx_oarray_init (mx_oarray_pt poarray, mx_oarray_sort_t sort);
void mx_oarray_node_init (mx_oarray_node_pt pnode, mx_usize_t seque);
void mx_oarray_remove (mx_oarray_node_pt pnode);
void mx_oarray_add (mx_oarray_pt poarray, mx_oarray_node_pt pnode);
mx_oarray_node_pt mx_oarray_get (mx_oarray_pt poarray, mx_usize_t index);
mx_size_t mx_oarray_index (mx_oarray_node_pt pnode);
mx_size_t mx_oarray_count (mx_oarray_pt parray);
mx_bool_t mx_oarray_iscontain (mx_oarray_pt parray, mx_oarray_node_pt pnode);

#endif
